/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

import observer from '@ohos.telephony.observer';
import radio from '@ohos.telephony.radio';
import sim from '@ohos.telephony.sim';
import wifi from '@ohos.wifi';
import Log from '../xlog/Log';
import connection from '@ohos.net.connection'
import bundle from '@ohos.bundle';
import { Callback } from '@ohos.base';
import GlobalContext from '../GlobalContext';

let contt:ESObject

class NetStatusUtil {
  private static readonly TAG: string = "MicroMsg.NetStatusUtil";
  public static readonly NON_NETWORK: number = -1;
  public static readonly WIFI: number = 0;
  public static readonly UNINET: number = 1;
  public static readonly UNIWAP: number = 2;
  public static readonly WAP_3G: number = 3;
  public static readonly NET_3G: number = 4;
  public static readonly CMWAP: number = 5;
  public static readonly CMNET: number = 6;
  public static readonly CTWAP: number = 7;
  public static readonly CTNET: number = 8;
  public static readonly MOBILE: number = 9;
  public static readonly LTE: number = 10;
  public static readonly NETWORK_TYPE_WIFI = 7;
  /**
   * No specific network policy, use system default.
   */
  public static readonly POLICY_NONE: number = 0x0;
  /**
   * Reject network usage on metered networks when application in background.
   */
  public static readonly POLICY_REJECT_METERED_BACKGROUND: number = 0x1;

  public static readonly TBACKGROUND_NOT_LIMITED: number = 0x0;
  public static readonly TBACKGROUND_PROCESS_LIMITED: number = 0x1;
  public static readonly TBACKGROUND_DATA_LIMITED: number = 0x2;
  public static readonly TBACKGROUND_WIFI_LIMITED: number = 0x3;

  public static readonly NO_SIM_OPERATOR: number = 0;
  contt = GlobalContext.getContext().getValue('context')
  public static dumpNetStatus() {
    radio.getNetworkState((err, data) => {
      Log.i(NetStatusUtil.TAG+':err-->', JSON.stringify(err))
      Log.i(NetStatusUtil.TAG+':data-->', JSON.stringify(data))
    });
  }

  public static isConnected(callback: Callback<boolean>) {
    if (NetStatusUtil.isWifi()) {
      callback(true)
      return
    }
    NetStatusUtil.getNetType((data) => {
      callback(data != radio.NetworkType.NETWORK_TYPE_UNKNOWN)
    })
  }

  public static getNetTypeString(callback: Callback<string>) {
    NetStatusUtil.getNetWorkType((netType) => {
      switch (netType) {
        case NetStatusUtil.MOBILE:
          callback('MOBILE');
          break;
        case NetStatusUtil.NETWORK_TYPE_WIFI:
          callback('WIFI');
          break;
        case radio.NetworkType.NETWORK_TYPE_UNKNOWN:
          callback('NON_NETWORK');
          break;
      }
    })
  }

  public static getNetWorkType(callback: Callback<number>) {
    if (NetStatusUtil.isWifi()) {
      callback(NetStatusUtil.NETWORK_TYPE_WIFI);
      return
    }
    radio.isRadioOn((err, data) => { //判断主卡是否打开
      if (data) {
        radio.getPrimarySlotId((err, data) => { //获取主卡的索引
          radio.getSignalInformation(data).then((signalInformations) => { //从主卡中获取支持类型网络信息
            if (signalInformations.length > 0) {
              switch (signalInformations[0].signalType) {
                case radio.NetworkType.NETWORK_TYPE_GSM:
                case radio.NetworkType.NETWORK_TYPE_CDMA:
                case radio.NetworkType.NETWORK_TYPE_WCDMA: //3g 联通通讯标准
                case radio.NetworkType.NETWORK_TYPE_TDSCDMA: // 3g
                case radio.NetworkType.NETWORK_TYPE_LTE: //3g 和4g 过度的标准
                case radio.NetworkType.NETWORK_TYPE_NR: // 5g
                  callback(NetStatusUtil.MOBILE);
                  break
                default:
                  callback(radio.NetworkType.NETWORK_TYPE_UNKNOWN);
                  break
              }
            } else {
              callback(radio.NetworkType.NETWORK_TYPE_UNKNOWN);
            }
          })
        })
      } else {
        callback(radio.NetworkType.NETWORK_TYPE_UNKNOWN);
      }
    })
  }
  /**
   * number对应radio.NetworkType
   * @param callback
   */
  public static getNetType(callback: Callback<number>): void {
    if (NetStatusUtil.isWifi()) {
      callback(NetStatusUtil.NETWORK_TYPE_WIFI);
      return
    }
    NetStatusUtil.getSimNetType(callback);
  }

  private static getSimNetType(callback: Callback<number>) {
    radio.isRadioOn((err, data) => { //判断主卡是否打开
      if (data) {
        radio.getPrimarySlotId((err, data) => { //获取主卡的索引
          radio.getSignalInformation(data).then((signalInformations) => { //从主卡中获取支持类型网络信息
            if (signalInformations.length > 0) {
              callback(signalInformations[0].signalType)
            } else {
              callback(radio.NetworkType.NETWORK_TYPE_UNKNOWN)
            }
          })
        })
      } else {
        callback(radio.NetworkType.NETWORK_TYPE_UNKNOWN);
      }
    })
  }

  public static getISPCode(callback: Callback<number>) {
    sim.getSimOperatorNumeric(0, (err, data) => {
      let simOperator: string = data;
      if (simOperator == null || simOperator.length < 5) { // IMSI
        callback(NetStatusUtil.NO_SIM_OPERATOR)
      }
      let len: number = simOperator.length;
      if (len > 6) {
        len = 6;
      }
      let MCC_MNC: string = '';
      for (let i: number = 0; i < len; i++) {
        let charString: string = simOperator.charAt(i);
        if (!(charString != null && !isNaN(Number(charString)))) {
          if (MCC_MNC.length <= 0) { // not begin concat
            continue;
          } else {
            break;
          }
        }
        MCC_MNC = MCC_MNC.concat(simOperator.charAt(i));
      }
      callback(Number(MCC_MNC).valueOf())
    });
  }

  public static getISPName(callback: Callback<string>) {
    sim.getSimSpn(0, (err, data) => {
      if (data == null || data == undefined) {
        callback('')
      }
      let MAX_LENGTH: number = 100;
      if (data.length <= MAX_LENGTH) {
        callback(data)
      } else {
        callback(data.substring(0, MAX_LENGTH))
      }
    });
  }

  public static guessNetSpeed(callback: Callback<number>) {
    if (NetStatusUtil.isWifi()) {
      callback(100 * 1024);
      return
    }
    radio.isRadioOn((err, data) => { //判断主卡是否打开
      if (data) {
        radio.getPrimarySlotId((err, data) => { //获取主卡的索引
          radio.getRadioTech(data, (err, radioTech) => {
            switch (radioTech.csRadioTech.valueOf()) {
              case radio.RadioTechnology.RADIO_TECHNOLOGY_GSM:
                callback(4 * 1024);
                break
              case radio.RadioTechnology.RADIO_TECHNOLOGY_1XRTT:
              case radio.RadioTechnology.RADIO_TECHNOLOGY_WCDMA:
              case radio.RadioTechnology.RADIO_TECHNOLOGY_HSPA:
              case radio.RadioTechnology.RADIO_TECHNOLOGY_HSPAP:
              case radio.RadioTechnology.RADIO_TECHNOLOGY_TD_SCDMA:
              case radio.RadioTechnology.RADIO_TECHNOLOGY_EVDO:
              case radio.RadioTechnology.RADIO_TECHNOLOGY_EHRPD:
              case radio.RadioTechnology.RADIO_TECHNOLOGY_LTE:
              case radio.RadioTechnology.RADIO_TECHNOLOGY_LTE_CA:
              case radio.RadioTechnology.RADIO_TECHNOLOGY_IWLAN:
              case radio.RadioTechnology.RADIO_TECHNOLOGY_NR: // 5G
                callback(100 * 1024);
                break;
              case radio.RadioTechnology.RADIO_TECHNOLOGY_UNKNOWN:
              default:
                callback(100 * 1024);
                break;
            }
          });
        })
      } else {
        callback(100 * 1024);
      }
    })
  }

  public static isMobile(callback: Callback<boolean>) {
    NetStatusUtil.getNetWorkType((netType) => {
      callback(netType == NetStatusUtil.MOBILE)
    })
  }

  public static is2G(callback: Callback<boolean>) {
    NetStatusUtil.getSimNetType((netType) => {
      callback(netType == radio.NetworkType.NETWORK_TYPE_GSM || netType == radio.NetworkType.NETWORK_TYPE_CDMA)
    })
  }

  public static is3G(callback: Callback<boolean>) {
    NetStatusUtil.getSimNetType((netType) => {
      if (netType == radio.NetworkType.NETWORK_TYPE_WCDMA
      || netType == radio.NetworkType.NETWORK_TYPE_TDSCDMA
      ) {
        callback(true)
      } else {
        callback(false)
      }
    })
  }

  public static is4G(callback: Callback<boolean>) {
    NetStatusUtil.getSimNetType((netType) => {
      callback(netType == radio.NetworkType.NETWORK_TYPE_LTE)
    })
  }

  public static is5G(callback: Callback<boolean>) {
    NetStatusUtil.getSimNetType((netType) => {
      callback(netType == radio.NetworkType.NETWORK_TYPE_NR)
    })
  }
// ohos中没有wap，所以该代码块注释
//  public static isWap(): boolean {
//    let type: number = NetStatusUtil.getNetType();
//    return NetStatusUtil.isWapBoolean(type);
//  }
//
//  public static isWapBoolean(type: number): boolean {
//    return type == NetStatusUtil.UNIWAP || type == NetStatusUtil.CMWAP
//    || type == NetStatusUtil.CTWAP || type == NetStatusUtil.WAP_3G;
//  }

  public static isWifi(): boolean{
    return wifi.isConnected() && wifi.isWifiActive()
  }

  public static isWifiBoolean(type: number): boolean {
    return type == NetStatusUtil.NETWORK_TYPE_WIFI;
  }

  public static getWifiInfo(callback: Callback<wifi.WifiLinkedInfo>) {
    wifi.getLinkedInfo((err, data) => {
      if (err) {
        callback(null)
      } else {
        callback(data)
      }
    });
  }

  public static searchIntentByClass(bundleName: string, abilityName: string, callBack: Callback<ESObject>) {
    bundle.getAbilityInfo(bundleName, abilityName)
      .then((abilityData) => {
        console.info('Operation successful. Data: ' + JSON.stringify(abilityData));
        let str = {
          'want': {
            'bundleName': bundleName,
            'abilityName': abilityName,
          },
        };
        contt.startAbility(str).then((data) => {
          Log.i('searchIntentByClass', 'success: ');
          callBack(abilityData)
        }).catch((error) => {
          Log.i('searchIntentByClass', 'failed: ' + JSON.stringify(error));
          callBack(null)
        })
      }).catch((error) => {
      console.error('Operation failed. Cause: ' + JSON.stringify(error));
      callBack(null)
    })
  }

  public static startSettingItent(type: number) {
    switch (type) {
      case NetStatusUtil.TBACKGROUND_NOT_LIMITED:
      case NetStatusUtil.TBACKGROUND_DATA_LIMITED:
      case NetStatusUtil.TBACKGROUND_PROCESS_LIMITED:
      case NetStatusUtil.TBACKGROUND_WIFI_LIMITED: {
        let str = {
          'want': {
            'bundleName': 'com.ohos.settings',
            'abilityName': 'com.ohos.settings.MainAbility',
            'uri': 'wifi'
          },
        };
        contt.startAbility(str).then((data) => {
          Log.i('startSettingItent', 'jumpToMms,success: ');
        }).catch((error) => {
          Log.i('startSettingItent', 'jumpToMms,failed: ');
        })
        break;
      }
    }
  }

//    ets没有对应设置wifi休眠政策
//    public static getWifiSleeepPolicy(): number {
//        return Settings.System.getInt(context.getContentResolver(), Settings.System.WIFI_SLEEP_POLICY, Settings.System.WIFI_SLEEP_POLICY_NEVER);
//    }

  public static isLimited(type: number): boolean {
    return type == NetStatusUtil.TBACKGROUND_DATA_LIMITED
      || type == NetStatusUtil.TBACKGROUND_PROCESS_LIMITED
      || type == NetStatusUtil.TBACKGROUND_WIFI_LIMITED;
  }

//  ohos没有关于后台进程限制
//  public static int getBackgroundLimitType(Context context) {
//    if (android.os.Build.VERSION.SDK_INT < 14) {
//    } else {
//      try {
//          Class<?> activityManagerNative = Class.forName("android.app.ActivityManagerNative");
//          Object am = activityManagerNative.getMethod("getDefault").invoke(activityManagerNative);
//          Object limit = am.getClass().getMethod("getProcessLimit").invoke(am);
//          if ((Integer) limit == 0) {
//              return TBACKGROUND_PROCESS_LIMITED;
//          }
//      } catch (Exception e) {
//          e.printStackTrace();
//      }
//    }
//    try {
//      int policy = getWifiSleeepPolicy(context);
//      if (policy == Settings.System.WIFI_SLEEP_POLICY_NEVER || (getNetType(context) != WIFI)) {
//          return TBACKGROUND_NOT_LIMITED;
//      } else if (policy == Settings.System.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED || policy == Settings.System.WIFI_SLEEP_POLICY_DEFAULT) {
//          return TBACKGROUND_WIFI_LIMITED;
//      }
//    } catch (Exception e) {
//      e.printStackTrace();
//    }
//
//    return TBACKGROUND_NOT_LIMITED;
//  }

  public static isImmediatelyDestroyActivities(): boolean {
    // var context = ability_featureAbility.getContext();
    // context.getAbilityInfo((error, data)=>{
    //   if (error) {
    //     console.error('Operation failed. Cause: ' + JSON.stringify(error));
    //     return;
    //   }
    //   console.info('Operation successful. Data:' + JSON.stringify(data));
    //   return data.backgroundModes != 0;
    // })
    return false;
  }

  public static getProxyInfo(strProxy: string, callback: Callback<number>) {
    connection.getDefaultNet()
      .then(netHandle => {
        console.info('getProxyInfo getDefaultNet success netHandle: ' + JSON.stringify(netHandle));
        connection.getConnectionProperties(netHandle)
          .then(connectionProperties => {
            console.info('getConnectionProperties success. connectionProperties: ' + JSON.stringify(connectionProperties));
            let proxyPort = connectionProperties.dnses[0].port;
            strProxy.concat(proxyPort.toString());
            callback(proxyPort);
          })
          .catch(err => {
            console.error('getConnectionProperties failed. err: ' + JSON.stringify(err));
            callback(0);
          })
      }).catch(err => {
      console.error('getProxyInfo getDefaultNet failed err: ' + JSON.stringify(err));
      callback(0);
    })
  }

  public static isKnownDirectNet(callback: Callback<boolean>) {
    NetStatusUtil.getNetType((dataType) => {
      callback(radio.NetworkType.NETWORK_TYPE_UNKNOWN != dataType)
    })
  }

  public static isNetworkConnected(callback:Callback<boolean>): void {
    connection.hasDefaultNet(function (error, has) {
      console.log(JSON.stringify(error))
      console.log('has: ' + has)
      callback(has)
    })
  }

  public static NETTYPE_NOT_WIFI: number = 0;
  public static NETTYPE_WIFI: number = 1;

  public static UNKNOW_TYPE: number = 999;

  private static nowStrength: number = 0;

  public static getNetTypeForStat(callback: Callback<number>) {
    NetStatusUtil.getNetType(data => {
      console.info('getNetTypeForStat data is ' + data);
      if (data == NetStatusUtil.NETWORK_TYPE_WIFI) {
        callback(NetStatusUtil.NETWORK_TYPE_WIFI);
      } else {
        callback(data == radio.NetworkType.NETWORK_TYPE_UNKNOWN ? NetStatusUtil.UNKNOW_TYPE : data * 1000);
      }
    })
  }

  public static getStrength(callback: Callback<number>) {
    NetStatusUtil.getNetTypeForStat((data) => {
      console.info('getStrength callback data: ' + JSON.stringify(data));
      if (data == NetStatusUtil.NETWORK_TYPE_WIFI) {
        wifi.getLinkedInfo(
          (err, data) => {
            if (err) {
              console.error('get wifi linked info error: ' + JSON.stringify(err));
              callback(0);
            } else {
              console.info("get wifi linked info: " + JSON.stringify(data));
              callback(Math.abs(data.rssi));
            }
          });
      } else {
        observer.on("signalInfoChange", (data) => {
          console.info("signalInfoChange data: " + JSON.stringify(data));
          if (data && data.length > 0) {
            NetStatusUtil.nowStrength = data[0].signalLevel;
          }
          callback(NetStatusUtil.nowStrength);
        });
      }
    })
  }
}

export default NetStatusUtil;